(function(cuiPackage){
	/**
	 * @class CUI.CEditor
	 * 文档编辑器
	 * @singleton
	 * @author cqb
	 * @version 1.0
	 */
	cuiPackage.Class("CEditor",cuiPackage.Object, {
		plugins: {},
		frame: null,
		doc: null,
		editor: null,
		toolbar: null,
		style: "theme/docstyle.css",
		tools: ["html","|","bold","italic","strike","|","alignleft","aligncenter","alignright","justify","|",
			"indent","outdent","list","unolist","|","fontname","fontcolor","fontsize","|","horizontal",
			"undo","|","redo","link","|","unlink","insertimg","print"],
		/**
         * @description 设置参数信息
         * @private
         * @param {options} 参数
         */
        _initialize : function(options){
        	cuiPackage.Object.prototype._initialize.apply(this, arguments);
			
			this._render();
        },
		
		/**
		 * 组件执行入口
		 */
		_render: function(){
			//创建
			this._create();
			//初始化
			this._init();
		},
		
		_create: function(){
			$(this.target).addClass("cui-editor-textarea");
			
			var editor = $("<div>").addClass("cui-ceditor");
			$(this.target).wrap(editor);
			
			this.frame = $('<iframe frameborder="0" scrolling="auto" class="cui-editor-frame"></iframe>');
			$(this.target).after(this.frame);
			
			var toolbar = $("<ul>").addClass("cui-ceditor-toolbar");
			$(this.target).before(toolbar);
			this.toolbar = toolbar;
			
			for(var i in this.tools){
				var name = this.tools[i];
				var plugin = this.plugins[name];
				if (plugin) {
					var bt = $("<li>");
					var a = $("<a href='javascript: void(0);' title='" + plugin.title + "'></a>").addClass("cui-editor-toolbaritem");
					a.addClass("cui-editor-tbitem-" + plugin.name);
					a.data("plugin-name", plugin.name);
					bt.append(a);
					toolbar.append(bt);
				}
				if(name == "|"){
					var bt = $("<li>");
					var a = $("<a href='javascript: void(0);'></a>").addClass("cui-editor-separate");
					bt.append(a);
					toolbar.append(bt);
				}
			}
		},
		
		_init: function(){
			this.frame.height($(this.target).outerHeight(true))
						.width($(this.target).outerWidth(true));
			
			$(this.target).parent().width($(this.target).outerWidth(true));
			for (var i in this.tools) {
				var name = this.tools[i];
				var plugin = this.plugins[name];
				if (plugin) {
					cuiPackage.CPlugin.init(this, plugin.name);
				}
			}
			var self = this;
			var editor = $(this.target).parent();
			editor.find(".cui-editor-toolbaritem").hover(function(){
				$(this).addClass("hover");
			},function(){
				$(this).removeClass("hover");
			});
			editor.find(".cui-editor-toolbaritem").each(function(){
				var name = $(this).data("plugin-name");
				var plugin = self.plugins[name];
				if(plugin.toggle){
					$(this).toggle(function(){
						CUI.CPlugin.call(self, name, "toggleF", [this]);
						return false;
					},function(){
						CUI.CPlugin.call(self, name, "toggleS", [this]);
						return false;
					});
				}else{
					$(this).click(function(){
						CUI.CPlugin.exec(self, name, [this]);
						return false;
					});
				}
			});
			
			var html = $(this.target).val();
			
			this.doc = this.getDoc(this.frame[0]);
			this.editor = this.enable(html);
			
			this.observeFocus();
			//this.keyUpListener();
			this.documentlistener();
			this.focus();
		},
		
		/**
		 * 监听键盘事件
		 */
		keyUpListener: function(){
			var self = this;
			$(this.doc).keyup(function(e){
				var key = e.keyCode || e.which;
				if (key === 13 && !e.shiftKey && !e.ctrlKey && !e.metaKey){
					return self.formatNewLine(e);
				}
				self.syncCode();
			});
		},
		
		/**
		 * document点击事件 将下拉的内容隐藏
		 */
		documentlistener: function(){
			var self = this;
			$(document).click(function(e){
				if (!$(e.target).parents(".ceditor-dropdown").length) {
					var dropdowns = $(self.toolbar).children(".ceditor-dropdown:visible");
					if (dropdowns.length) {
						dropdowns.hide();
						$(self.toolbar).find("a.cui-editor-toolbaritem.active").removeClass("active");
					}
				}
			});
			
			$(this.doc).click(function(){
				var dropdowns = $(self.toolbar).children(".ceditor-dropdown:visible");
				if(dropdowns.length){
					dropdowns.hide();
				}
			});
		},
		
		/**
		 * 同步内容
		 */
		syncCode: function(){
			var html = this.formatting(this.editor.html());
			$(this.target).val(html);
		},
		
		/**
		 * 换行
		 * @param {Object} e
		 */
		formatNewLine: function(e){
			//父节点
			var parent = this.getParentNode();
			if (parent.nodeName === 'BODY'){
				if (e.preventDefault){
					e.preventDefault();
				}
				
				var element = $(this.getCurrentNode());
				if (element.get(0).tagName === 'DIV' && (element.html() === '' || element.html() === '<br>')){
					var newElement = $('<p>').append(element.clone().get(0).childNodes);
					element.replaceWith(newElement);
					newElement.html('<br />');
					this.setFocusNode(newElement.get(0));

					this.syncCode();
					return false;
				}
				else{
					this.syncCode();
				}
			}
			else {
				this.syncCode();
				return true;
			}
		},
		
		/**
		 * 获取选中区域
		 */
		getSelection: function(){
			if (this.frame.get(0).contentWindow.getSelection){
				return this.frame.get(0).contentWindow.getSelection();
			}
			else if (this.frame.get(0).contentWindow.document.selection){
				return this.frame.get(0).contentWindow.document.selection.createRange();
			}
		},
		
		/**
		 * 得到父节点
		 */
		getParentNode:function(){
			if (window.getSelection){
				return this.getSelection().getRangeAt(0).startContainer.parentNode;
			}
			else if (document.selection){
				return this.getSelection().parentElement();
			}
		},
		
		/**
		 * 
		 */
		getCurrentNode:function(){
			if (window.getSelection){
				return this.getSelection().getRangeAt(0).startContainer;
			}
			else if (document.selection){
				return this.getSelection();
			}
		},
		/**
		 * 
		 * @param {Object} node
		 * @param {Object} toStart
		 */
		setFocusNode: function(node, toStart){
			var range = this.doc.createRange();

			var selection = this.getSelection();
			toStart = toStart ? 0 : 1;
	
			if (selection !== null){
				range.selectNodeContents(node);
				selection.addRange(range);
				selection.collapse(node, toStart);
			}
		},
		
		/**
		 * 获取文档对象
		 * @param {Object} frame
		 */
		getDoc:function(frame){
			if (frame.contentDocument){
				return frame.contentDocument;
			}
			else if (frame.contentWindow && frame.contentWindow.document){
				return frame.contentWindow.document;
			}
			else if (frame.document){
				return frame.document;
			}
			else{
				return null;
			}
		},
		
		/**
		 * 文档输出html
		 * @param {Object} html
		 */
		write: function(html){
			this.doc.open();
			this.doc.write(html);
			this.doc.close();
		},
		
		/**
		 * 使文档可以编辑
		 * @param {Object} html
		 */
		enable:function(html){
			if (this.doc !== null){
				this.write(this.setDoc(html));
				if ($.browser.mozilla){
					doc.execCommand("useCSS", false, true);
				}
				return $(this.doc).find('#page');
			}
			else{
				return false;
			}
		},
		
		/**
		 * 设置文档内容
		 * @param {Object} html
		 */
		setDoc:function(html){
			var frameHtml = '<!DOCTYPE html>\n' +
			'<html><head>' +
			'<link href="'+this.style+'" rel="stylesheet" type="text/css">'+
			'</head>'+
			'<body><div id="page" contenteditable="true" dir="ltr">' +
			html + 
			'</div></body></html>';
			
			return frameHtml;
		},
		
		/**
		 * 格式化
		 * @param {Object} html
		 */
		formatting: function(html){
			// lowercase
			if ($.browser.msie){
				var match = html.match(/<(.*?)>/gi);
				$.each(match, function(i,s){
					html = html.replace(s, s.toLowerCase());
				});
				html = html.replace(/style="(.*?)"/gi, function(w) { return w.toLowerCase(); });
				html = html.replace(/ jQuery(.*?)=\"(.*?)\"/gi, '');
			}

			html = html.replace(/<span([\w\W]*?)style="color:(.*?);"><span([\w\W]*?)style="background-color:(.*?);">([\w\W]*?)<\/span><\/span>/gi, '<span style="color: $2; background-color: $4;">$5</span>');
			html = html.replace(/<span([\w\W]*?)style="background-color:(.*?);"><span([\w\W]*?)style="color:(.*?);">([\w\W]*?)<\/span><\/span>/gi, '<span style="color: $2; background-color: $4;">$5</span>');

			html = html.replace(/<span([\w\W]*?)color="(.*?)">([\w\W]*?)<\/span\>/gi, '<span$1style="color: $2;">$3</span>');
			html = html.replace(/<font([\w\W]*?)color="(.*?)">([\w\W]*?)<\/font\>/gi, '<span$1style="color: $2;">$3</span>');
			html = html.replace(/<span style="(.*?)"\s+style="(.*?)"[\s]*>([\w\W]*?)<\/span\>/gi, '<span style="$1;$2">$3</span>');
			html = html.replace(/<font([\w\W]*?)>([\w\W]*?)<\/font\>/gi, "<span$1>$2</span>");
			html = html.replace(/<span>([\w\W]*?)<\/span>/gi, '$1');			

			// mini clean
			html = html.replace(/<p><p>/g, '<p>');
			html = html.replace(/<\/p><\/p>/g, '</p>');
			html = html.replace(/<hr(.*?)>/g, '<hr />');
			html = html.replace(/<p>&nbsp;/g, '<p>');
			html = html.replace(/<p><ul>/g, '<ul>');
			html = html.replace(/<p><ol>/g, '<ol>');
			html = html.replace(/<\/ul><\/p>/g, '</ul>');
			html = html.replace(/<\/ol><\/p>/g, '</ol>');
			html = html.replace( /<p(.*?)>&nbsp;<\/p>/gi, '');

			// remove formatting
			html = this.formattingRemove(html);

			// empty tags
			html = this.formattingEmptyTags(html);
						
			// add formatting before
			html = this.formattingAddBefore(html);
			
			// add formatting after
			html = this.formattingAddAfter(html);

			// indenting
			html = this.formattingIndenting(html);

			return html;
		},
		
		formattingRemove: function(html){
			html = html.replace(/\s{2,}/g, ' ');
			html = html.replace(/\n/g, ' ');	
			html = html.replace(/[\t]*/g, '');
			html = html.replace(/\n\s*\n/g, "\n");
			html = html.replace(/^[\s\n]*/g, '');
			html = html.replace(/[\s\n]*$/g, '');	
			html = html.replace(/>\s+</g, '><');
			
			return html;		
		},
		
		formattingIndenting:function (html){
			html = html.replace(/<li/g, "\t<li");
			html = html.replace(/<tr/g, "\t<tr");
			html = html.replace(/<td/g, "\t\t<td");
			html = html.replace(/<\/tr>/g, "\t</tr>");	
			
			return html;	
		},
		
		formattingEmptyTags:function (html)		{
			var etags = ["<pre></pre>","<blockquote>\\s*</blockquote>","<em>\\s*</em>","<ul></ul>","<ol></ol>","<li></li>","<table></table>","<tr></tr>","<span>\\s*<span>", "<span>&nbsp;<span>", "<b>\\s*</b>", "<b>&nbsp;</b>", "<p>\\s*</p>", "<p>&nbsp;</p>",  "<p>\\s*<br>\\s*</p>", "<div>\\s*</div>", "<div>\\s*<br>\\s*</div>"];
			for (var i = 0; i < etags.length; ++i)
			{
				var bbb = etags[i];
				html = html.replace(new RegExp(bbb,'gi'), "");
			}
			
			return html;
		},
		
		formattingAddBefore:function (html){
			var lb = '\r\n';
			var btags = ["<p", "<form","</ul>", '</ol>', "<fieldset","<legend","<object","<embed","<select","<option","<input","<textarea","<pre","<blockquote","<ul","<ol","<li","<dl","<dt","<dd","<table", "<thead","<tbody","<caption","</caption>","<th","<tr","<td","<figure"];
			for (var i = 0; i < btags.length; ++i)
			{
				var eee = btags[i];
				html = html.replace(new RegExp(eee,'gi'),lb+eee);
			}
			
			return html;
		},
		
		formattingAddAfter:function (html){
			var lb = '\r\n';		
			var atags = ['</p>', '</div>', '</h1>', '</h2>', '</h3>', '</h4>', '</h5>', '</h6>', '<br>', '<br />', '</dl>', '</dt>', '</dd>', '</form>', '</blockquote>', '</pre>', '</legend>', '</fieldset>', '</object>', '</embed>', '</textarea>', '</select>', '</option>', '</table>', '</thead>', '</tbody>', '</tr>', '</td>', '</th>', '</figure>'];
			for (var i = 0; i < atags.length; ++i)
			{
				var aaa = atags[i];
				html = html.replace(new RegExp(aaa,'gi'),aaa+lb);
			}
			
			return html;
		},
		
		focus: function(){
			this.editor.focus();
		},
		
		observeFocus: function(){
			if ($(this.doc).find('body').height() < $(this.frame.get(0).contentWindow).height()){
				$(this.doc).click($.proxy(function(e) { this.editor.focus();}, this));
			}
		},
		
		observeImages: function(){
			if ($.browser.mozilla){
				this.doc.execCommand("enableObjectResizing", false, "false");
			}
			
			$(this.doc).find('img').each($.proxy(function(i,s){
				if ($.browser.msie) {
					$(s).attr('unselectable', 'on');
				}
				this.resizeImage(s);
			}, this));
		},
		
		resizeImage: function(resize)
		{
			var clicked = false;
			var clicker = false;
			var start_x;
			var start_y;
			var ratio = $(resize).width()/$(resize).height();

			var y = 1;
			var x = 1;
			var min_w = 1;
			var min_h = 1;

			$(resize).hover(function() {$(resize).css('cursor', 'nw-resize'); }, function() { $(resize).css('cursor','default'); clicked=false; });

			$(resize).mousedown(function(e)
			{
				if (e.preventDefault)
				{
					e.preventDefault();
				}

				clicked = true;
				clicker = true;

				start_x = Math.round(e.pageX - $(resize).eq(0).offset().left);
				start_y = Math.round(e.pageY - $(resize).eq(0).offset().top);
			});
			
			$(resize).mouseup($.proxy(function(e){
				clicked = false;
			}, this));
			
			$(resize).click($.proxy(function(e){
				if (clicker){
					this.imageEdit(e);
				}
	
			}, this));

			$(resize).mousemove(function(e){
				if (clicked){
					clicker = false;
				
					var mouse_x = Math.round(e.pageX - $(this).eq(0).offset().left) - start_x;
					var mouse_y = Math.round(e.pageY - $(this).eq(0).offset().top) - start_y;
					
					var div_h = $(resize).height();
					
					var new_h = parseInt(div_h, 10) + mouse_y;
					var new_w = new_h*ratio;
					
					if (x === 1 || (typeof(x) === "number" && new_w < x && new_w > min_w)){
						$(resize).width(new_w);
					}
					if (y === 1 || (typeof(y) === "number" && new_h < y && new_h > min_h)){
						$(resize).height(new_h);
					}
					start_x = Math.round(e.pageX - $(this).eq(0).offset().left);
					start_y = Math.round(e.pageY - $(this).eq(0).offset().top);
				}
			});
		},
		imageEdit: function(ele){
			
		}
	});
	
})(jQuery.fn);